package com.yalu.file;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.yalu.entity.BillData;
import com.yalu.entity.BillDetailData;
import com.yalu.entity.BillDetailDataExcel;
import com.yalu.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.io.RandomAccessFile;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;

/**
 * 空中云汇对账单
 */
@Slf4j
@Component
public class AirwallexPdfRead {

    /**
     * 读PDF文件，使用了pdfbox开源项目
     *
     * @param fileName
     */
    public static void readPdf(String fileName, BigDecimal lastBalance, Map<String, BillData> map, BillData billData) {
        File file = new File(fileName);
        FileInputStream in = null;
        try {
            in = new FileInputStream(fileName);
            // 新建一个PDF解析器对象
            PDFParser parser = new PDFParser(new RandomAccessFile(file, "r"));
            // 对PDF文件进行解析
            parser.parse();
            // 获取解析后得到的PDF文档对象
            PDDocument pdfdocument = parser.getPDDocument();
            int pageSize = pdfdocument.getNumberOfPages();
            boolean isStart = false;
            for (int i = 0; i < pageSize; i++) {
                // 新建一个PDF文本剥离器
                PDFTextStripper stripper = new PDFTextStripper();
                // 设置按顺序输出
                stripper.setSortByPosition(true);
                stripper.setStartPage(i + 1);
                stripper.setEndPage(i + 1);
                String lineSepartor = stripper.getLineSeparator();
                // 从PDF文档对象中剥离文本
                String result = stripper.getText(pdfdocument);
                String[] resultArray = result.split(lineSepartor);
                int arrayLength = resultArray.length;
                Queue<BillDetailData> dataQueue = new LinkedList<>();
                Map<String, String> monthMap = new HashMap<>(12);
                monthMap.put("JAN", "01");
                monthMap.put("FEB", "02");
                monthMap.put("MAR", "03");
                monthMap.put("APR", "04");
                monthMap.put("MAY", "05");
                monthMap.put("JUN", "06");
                monthMap.put("JUL", "07");
                monthMap.put("AUG", "08");
                monthMap.put("SEP", "09");
                monthMap.put("OCT", "10");
                monthMap.put("NOV", "11");
                monthMap.put("DEC", "12");
                for (int y = 0; y < arrayLength; y++) {
                    if (null != resultArray[y] && resultArray[y].trim().length() > 0) {
                        String lineText = resultArray[y].replace(",", "").trim();
                        if ("Id Currency Currency Amount Rate Amount Amount Balance Balance".equals(lineText)) {
                            isStart = true;
                        } else {
                            if (isStart) {
                                Matcher matcher = CommonUtil.PATTERN.matcher(lineText);
                                if (matcher.find()) {
                                    BillDetailData detailData = new BillDetailData();
                                    String[] lineTextArray = lineText.split(" ");
                                    BillDetailData detailDataQueue = dataQueue.poll();
                                    dataQueue.offer(detailDataQueue);
                                    if (null != detailDataQueue) {
                                        dataQueue.poll();
                                        BeanUtils.copyProperties(detailDataQueue, detailData);
                                        dataQueue.offer(detailData);
                                    }
                                    detailData.setDate(lineTextArray[0]);
                                    detailData.setTransactionDetails(lineTextArray[1]);
                                    handleAmount(lineText, detailData, lastBalance, billData);
                                    boolean isHave = StringUtils.hasText(detailData.getBalance()) || StringUtils.hasText(detailData.getDeposit()) || StringUtils.hasText(detailData.getWithdrawal());
                                    if (StringUtils.hasText(detailData.getTransactionDetails()) && isHave) {
                                        billData.getDetailData().add(detailData);
                                        lastBalance = new BigDecimal(detailData.getBalance());
                                        detailData = new BillDetailData();
                                        dataQueue.poll();
                                        dataQueue.offer(detailData);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("读取PDF文件" + file.getAbsolutePath() + "生失败！" + e);
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                }
            }
        }

    }

    /**
     * 处理金额
     *
     * @param lineText
     * @param detailData
     * @param lastBalance
     */
    private static void handleAmount(String lineText, BillDetailData detailData, BigDecimal lastBalance, BillData billData) {
        List<String> amountList = new ArrayList<>();
        Matcher matcher = CommonUtil.PATTERN_T.matcher(lineText);
        while (matcher.find()) {
            amountList.add(matcher.group());
        }
        int size = amountList.size();
        if (size < 3) {
            log.warn("size小于3 ：{}", lineText);
            return;
        }
        String balance = amountList.get(size - 1).trim();
        String amount = amountList.get(size - 3).trim();
        if (amount.startsWith(".")) {
            amount = "0" + amount;
        }
        detailData.setBalance(balance);
        if (Objects.isNull(lastBalance)) {
            if (amount.equals(balance)) {
                BigDecimal amountDecimal = new BigDecimal(amount);
                if (amountDecimal.compareTo(BigDecimal.ZERO) >= 0) {
                    detailData.setDeposit(amount);
                    detailData.setTransactionDetails("存款");
                } else {
                    detailData.setWithdrawal(amount);
                    detailData.setTransactionDetails("提款");
                }
                BillDetailData balanceDetailData = new BillDetailData();
                balanceDetailData.setBalance("0");
                balanceDetailData.setTransactionDetails("承前结余");
                billData.getDetailData().add(balanceDetailData);
            } else {
                BigDecimal balanceDecimal = new BigDecimal(balance);
                BigDecimal amountDecimal = new BigDecimal(amount);
                if (balanceDecimal.compareTo(amountDecimal) >= 0) {
                    detailData.setDeposit(amount);
                    detailData.setTransactionDetails("存款");
                    BillDetailData balanceDetailData = new BillDetailData();
                    balanceDetailData.setBalance(balanceDecimal.subtract(amountDecimal).toString());
                    balanceDetailData.setTransactionDetails("承前结余");
                    billData.getDetailData().add(balanceDetailData);
                } else {
                    detailData.setWithdrawal(amount);
                    detailData.setTransactionDetails("提款");
                    BillDetailData balanceDetailData = new BillDetailData();
                    balanceDetailData.setBalance(balanceDecimal.add(amountDecimal).toString());
                    balanceDetailData.setTransactionDetails("承前结余");
                    billData.getDetailData().add(balanceDetailData);
                }
            }
        } else {
            BigDecimal balanceDecimal = new BigDecimal(balance);
            if (balanceDecimal.compareTo(lastBalance) >= 0) {
                detailData.setDeposit(amount);
                detailData.setTransactionDetails("存款");
            } else {
                detailData.setWithdrawal(amount);
                detailData.setTransactionDetails("提款");
            }
        }
    }


    /**
     * 测试pdf文件的创建
     *
     * @param args
     */
    public static void main(String[] args) {
        String filePath = "D://yalu//monthly//";  //这里先手动把绝对路径的文件夹给补上。
        LinkedList<String> filePaths = new LinkedList<>();
        recursionFile(filePath, filePaths);
        System.out.println("文件数量：" + filePaths.size());
        Map<String, BillData> map = new HashMap<>();
        BigDecimal lastBalance = null;
        String currency = "USD";
        BillData billData = new BillData();
        billData.setCurrency(currency);
        billData.setType("Savings");
        String key = billData.getCurrency().concat(billData.getType());
        billData.setDetailData(new ArrayList<>());
        map.put(key, billData);
        String year = "";
        for (String fileName : filePaths) {
            int lastIndex = fileName.lastIndexOf("\\");
            year = fileName.substring(lastIndex + 1, lastIndex + 5);
            readPdf(fileName, lastBalance, map, billData);
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String time = LocalDateTime.now().format(dtf);
        String outFileName = "D:\\yalu\\" + year + "年_月结单_airwallex_" + currency + "_" + time.substring(time.length() - 6) + ".xlsx";
        writerFils(map, outFileName);
    }

    /**
     * 写入文件
     *
     * @param map
     * @param outFileName
     */
    public static void writerFils(Map<String, BillData> map, String outFileName) {
        try {
            ExcelWriter excelWriter = EasyExcel.write(outFileName, BillDetailDataExcel.class).build();
            for (String key : map.keySet()) {
                BillData billData = map.get(key);
                String sheetName = "1";
                if ("Savings".equals(billData.getType())) {
                    sheetName = "月结单（" + billData.getCurrency() + "）";
                } else if ("Current".equals(billData.getType())) {
                    sheetName = "资金往来（" + billData.getCurrency() + "）";
                }
                BigDecimal depositSum = new BigDecimal(0);
                BigDecimal withdrawalSum = new BigDecimal(0);
                List<BillDetailDataExcel> list = new ArrayList<>(billData.getDetailData().size());
                for (BillDetailData billDetailData : billData.getDetailData()) {
                    BillDetailDataExcel billDetailDataExcel = new BillDetailDataExcel();
                    BeanUtils.copyProperties(billDetailData, billDetailDataExcel);
                    if (StringUtils.hasText(billDetailData.getDeposit())) {
                        depositSum = depositSum.add(new BigDecimal(billDetailData.getDeposit()));
                    }
                    if (StringUtils.hasText(billDetailData.getWithdrawal())) {
                        withdrawalSum = withdrawalSum.add(new BigDecimal(billDetailData.getWithdrawal()));
                    }
                    list.add(billDetailDataExcel);
                }
                if (0 < list.size()) {
                    BillDetailDataExcel firstData = list.stream().findFirst().get();
                    String balance = firstData.getBalance();
                    BigDecimal balanceDecimal = new BigDecimal(0);
                    if (StringUtils.hasText(balance)) {
                        balanceDecimal = balanceDecimal.add(new BigDecimal(balance));
                    }
                    balanceDecimal = balanceDecimal.add(depositSum).subtract(withdrawalSum);
                    BillDetailDataExcel billDetailDataExcel = new BillDetailDataExcel();
                    billDetailDataExcel.setDate("智能校对助手校对结果");
                    billDetailDataExcel.setTransactionDetails("上期结余：" + balance);
                    billDetailDataExcel.setDeposit("总收入：" + depositSum);
                    billDetailDataExcel.setWithdrawal("总支出：" + withdrawalSum);
                    billDetailDataExcel.setBalance(balanceDecimal.toString());
                    list.add(billDetailDataExcel);
                }
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
                excelWriter.write(list, writeSheet);
            }
            // 千万别忘记finish 会帮忙关闭流
            excelWriter.finish();
        } catch (Exception e) {
            log.error("文件写入失败：", e);
        }
    }

    /**
     * 递归文件
     *
     * @param path
     * @param filePaths
     */
    public static void recursionFile(String path, LinkedList<String> filePaths) {
        if (StringUtils.hasText(path)) {
            File file = new File(path);
            for (File f : file.listFiles()) {
                if (f.isDirectory()) {
                    recursionFile(f.getPath(), filePaths);
                } else {
                    if (f.getPath().contains(".pdf")) {
                        filePaths.add(f.getPath());
                    }
                }
            }
        }
    }

}
